package deibay.server.network;


import java.util.Hashtable;
import java.util.logging.Level;
import deibay.DeibayLogger;
import deibay.messages.Message;
import deibay.network.IClientCommunicator;
import deibay.network.ServerCommunicator;
import deibay.server.EventConsumer;
import deibay.server.ServerManager;
import deibay.server.events.Event;
import deibay.server.events.CreateSessionEvent;
import deibay.server.events.RemoveSessionEvent;
import deibay.server.events.SendAdvertiseEvent;
import deibay.server.events.SendMessageEvent;
import deibay.server.network.socket.SocketServer;
import deibay.server.network.socket.UDPService;
import deibay.users.User;


/**
 * @author   Joel Cordeiro
 */
public class NetworkManager implements EventConsumer{

	private Hashtable<String ,Session> sessions = null;
	private ClientSessionActivity tClientsConnections = null;
	private ServerCommunicator server = null;	
	private Thread tSessionsActivity = null; 
	private UDPService udpService = null;
	
	public NetworkManager()
	{
		sessions = new Hashtable<String, Session>();				
	}

	public void init()
	{
		server = new SocketServer();
		udpService = new UDPService();
		tClientsConnections = new ClientSessionActivity(sessions);
		subscribeToEvents();
		initializeThreads();
	}
	
	private void subscribeToEvents() {		
		ServerManager.getInstance().getEventManager().subscribe(this, CreateSessionEvent.class);
		ServerManager.getInstance().getEventManager().subscribe(this, SendMessageEvent.class);
		ServerManager.getInstance().getEventManager().subscribe(this, RemoveSessionEvent.class);
		ServerManager.getInstance().getEventManager().subscribe(this, SendAdvertiseEvent.class);		
	}

	private void initializeThreads() 
	{
		Thread tServer = new Thread(server);
		tServer.start();		
		tSessionsActivity = new Thread(tClientsConnections);
		tSessionsActivity.start();				
	}

	private synchronized void addSession(Session session)
	{		
		synchronized(sessions) {
			sessions.put(session.getUser().getId(), session);
			if (sessions.size() == 1)
			{
				sessions.notifyAll();
			}
		}
		
		DeibayLogger.getInstance().getLog().log(Level.WARNING, "Foi adicionada uma sessao ao utilizador '"+session.getUsername()+"'.\n");
	}
	
	private synchronized void removeSession(Session session)
	{
		this.sessions.remove(session.getUser().getId());	
	}
	
	public void handleEvent(Event event) {
		if(event instanceof CreateSessionEvent)
		{
			User user = ((CreateSessionEvent)event).getNewSessionArgs().getUser();
			IClientCommunicator clientCommunicator = ((CreateSessionEvent)event).getNewSessionArgs().getClientCommunicator(); 
			Session session = sessions.get(user.getId());
			if(session != null)
			{
				session.recoverSession(clientCommunicator);
			}
			else 
			{
				session = new Session(clientCommunicator, user);
				addSession(session);
			}
		}
		else if(event instanceof SendMessageEvent)
		{
			String user = ((SendMessageEvent)event).getSendMessageArg().getUser();
			Message message = ((SendMessageEvent)event).getSendMessageArg().getMessage();
			//System.err.println(">>>> SENDING MESSAGE " + message);
			//System.err.println(sessions.get(user));			
			//System.err.println(user);
			if(sessions.get(user) != null)
			{
				Session session = sessions.get(user);
				session.sendMessage(message);
			}
		}
		else if(event instanceof SendAdvertiseEvent)
		{
			Message msg = ((SendAdvertiseEvent)event).getSendAdvertiseArgs().getMsg();
			udpService.sendMessage(msg);
		}
		else if(event instanceof RemoveSessionEvent)
		{
			Session session = ((RemoveSessionEvent)event).getRemoveSessionEventArg().getSession();
			session.getCommunicator().close();
			removeSession(session);
		}
		
	}		
}
